﻿using System;
using System.Collections.Generic;

namespace interface_接口
{
    class Program
    {
        static void Main(string[] args)
        {
            A a = new A("耀");
            a.Drink("可乐");
            a.Drink("矿泉水");
            a.eat();
            ((inter)a).Eat();
            Console.WriteLine("--------------");
            inter inta = new A("sha");//里氏转换：父类给子类代言，在这是接口来代言
            inta.Drink("a");

            Console.WriteLine("*******索引器**************");
            A p1 = new A("555");
            p1.Drink("可乐0");
            p1.Drink("可乐1");
            p1.Drink("可乐2");
            p1.Drink("可乐3");
            p1.Drink("可乐4");
            var index = 3;
            Console.WriteLine($"{p1.name}第{index+1}次喝了{p1[index]}");
            index = 5;
            Console.WriteLine($"{p1.name}第{index + 1}次喝了{p1[index]}");

            Console.WriteLine("******事件*******");
            A p2 = new A("张无极");
            p2.event1 += p2_event1;// 谁关心，谁订阅（我测试，我关心，我订阅,你添油加醋）
            p2.eat();
        }
        private static void p2_event1(A person)
        {
            Console.WriteLine($"{person.name}在偷偷的吃东西！");
        }
    }
    //接口关键字：interface 门面 GUI
    //1.接口不允许实现具体方法，（但在新语法中可以实现具体方法，但是必须调用这个接口来声明，而不是用继承接口的这个类型声明）
    //2. 新语法中，可以实现具体的方法，同时，不写访问修饰符，依旧可以访问(接口成员会自动成为公共成员)，而类型却不能。
    //3.在新语法中接口里实现方法了，继承了接口的那个类可以实现也可以不实现，而如果接口中没有实现那个方法，那么继承接口的类中必须实现。
    //4.继承类中具体实现的方法，继承类中如果不实现接口中的方法，那么用接口声明来调用，会输出接口中的方法，如果继承类中实现了接口的方法，那么就会输出类本身这个方法。
    //5.接口不能包含实例字段。接口不能包含常量（新的语法中 能够包含常量）
    //6.接口不能实现包含实例的构造函数
    //7.接口不能带有析构函数，报错：只有类类型才能有
    //8.接口能包含类类型
    //9.接口内的 方法、属性、索引器、事件
    //10.接口能包含public 、protected 访问修饰符，如果 private 那就需要实现具体的方法
    //11.从现在的语法特性来看，Interface 和 class 好像没区别了
    //12.接口类型的字段成员可以是 静态类型,和 class 行为保持一致，但是不支持 static void EatA();
    //13.当类类型和 结构类型实现接口时，为接口定义的所有抽象成员提供实现
    //14.不同于 class ，Interface 可以被多继承，class 只能继承一个基类
    //interface inter1 { }// 接口的继承，和 class 继承一样的表现行为：能力和行为的继承
    // interface inter2 { }
    interface inter //:inter1,inter2//接口可以继承多个
    {
        /// <summary>
        /// 容量
        /// </summary>
        int Capacity { get; set; }//接口中的属性
        //public inter()//接口中不能包含构造函数
        //{

        //}
        //public string name;//接口中不能包含实例字段
        class B//在接口中可以包含类 类型
        {
            public string name;
        }
        const int a=100;//接口中可以包含常量
          void Eat()//接口中的方法
        {
            Console.WriteLine("我是接口中的吃");
        }
        static void EatA()//加上static必须有主体。
        {

        }
        //void Drink();//接口中无实现的方法
        // interface 定义的方法实现的时候使用 virtual 来修饰，实现多态，接口跟多态也产生了化学反应
        public virtual void Output()
        {
        }

        // 索引器（Indexer） 允许一个对象可以像数组一样使用下标的方式来访问。
        //当您为类定义一个索引器时，该类的行为就会像一个 虚拟数组（virtual array） 一样。
        //您可以使用数组访问运算符[] 来访问该类的的成员(在本例中，通过索引器访问的是 Drinks 集合)。
        List<string> Drinks { get; set; }//可读可写
        string this [int inedx] { get; }//只读 接口中的索引器
        /// <summary>
        /// 喝
        /// </summary>
        /// <param name="name">饮料名称</param>
        void Drink(string name);
        // event 关键字，表示事件 ，Action ：无返回值委托，OnEatSomething 声明的事件的字段名
        //// OnEatSomething = on(当xxx的时候) + Eat （吃）+Something （任意的某些东西）
        event Action<A> event1;//接口中的事件
        //Action 表示没有返回值委托
        //Func 表示有返回值的委托
        //Delegate委托

    }
    class A:inter
    {
        public int capacity;

        public string this[int inedx]//关键字this   访问修饰符+返回值的类型+this+[int inedx] 这几个组成了索引器
        {
            get
            {
                //Count计数，用来计算Drinks里面有多少值
                // get 、set 、value 是一个套件，用在属性或者索引器
                // 接口中 索引器的实现
                if (Drinks.Count > inedx)//如果Drinks中的数大于我给定的inedx
                {
                    return Drinks[inedx];//就返回当前储存的东西
                }
                return "我没有喝那么多水";
            }
        }
        public List<string> Drinks { get; set; }//自动属性
        // => 是方法表达式主体 ；{} 方法体 ；方法体内只有一行逻辑的他俩可以互相替换
        public int Capacity { get => capacity; set => capacity = value; }

        public string name;

        public event Action<A> event1;

        public A(string name)//构造函数
        {
            this.name = name;//将name字段进行实例
            Drinks = new List<string>();//将Drinks也进行实例
        }
        

         public void eat()
        {
            //Invoke :执行
            // ?.  为空判定
            // 事件监听全部 -= 之后，会为 Null 
            // 事件的生命周期：声明→监听（订阅）->执行
            event1?.Invoke(this);
            Console.WriteLine("我是A类中的吃");
        }

        public void Drink(string name)
        {
            Drinks.Add(name);
            Console.WriteLine($"{this.name}喝了{name}");
        }

    }

}
